/*
 * Bind.h
 *
 *
 *  Created on: May 19, 2013
 *      Author: Lucifer
 */

#ifndef	__BIND_H__
#define	__BIND_H__

namespace BFX
{
namespace _PRIV
{

////////////////////////////////////////////////////////////////////////////////
// placeholders

/*
 * This class uses to determine whether the target type is placeholder or not.
 * This is the basic implementation for any types.
 */
template<class T>
struct IsPlaceHolder
{
	enum _vt
	{
		value = 0
	};
};

/*
 * This class represents a placeholder.
 */
template<int I>
struct PlaceHolder
{
	PlaceHolder()
	{
	}

	template<class T>
	PlaceHolder(const T& i)
	{
		// NOTE: static_assert
		typedef char dummy[(I == IsPlaceHolder<T>::value) ? 1 : -1];
	}
};

/*
 * This class uses to determine whether the target type is placeholder or not.
 * This is the extended implementation for placeholder.
 */
template<int N>
struct IsPlaceHolder<PlaceHolder<N> >
{
	enum
	{
		value = 1
	};
};

/*
 * The type wrapper.
 */
template<class T>
struct TypeT
{
};

/*
 * The value wrapper.
 */
template<class T>
class ValueT
{
public:
	ValueT(const T& t) :
			m_t(t)
	{
	}

	T & Get()
	{
		return m_t;
	}
	const T& Get() const
	{
		return m_t;
	}

	bool operator==(const ValueT& rhs) const
	{
		return m_t == rhs.m_t;
	}

private:
	T m_t;
};

/*
 * Represents an argument. There have two cases for the argument, placeholder or value.
 */
template<class T>
struct Argument
{
	typedef ValueT<T> TYPE;
};
template<class T>
struct Argument<ValueT<T> >
{
	typedef ValueT<T> TYPE;
};
template<int I>
struct Argument<PlaceHolder<I> >
{
	typedef PlaceHolder<I> TYPE;
};

////////////////////////////////////////////////////////////////////////////////
// 0-N templates.

/*
 * This class mapping an object with a member function and to a functor object.
 * This implementation provided no argument.
 */
template<class R, class T>
struct MemberFunctionT0
{
	typedef R (T::*F)();
	explicit MemberFunctionT0(F f) :
			m_f(f)
	{
	}
	R operator()(T* p) const
	{
		return (p->*m_f)();
	}
	F m_f;
};
/*
 * This class mapping an object with a const member function and to a functor object.
 * This implementation provided no argument.
 */
template<class R, class T>
struct ConstMemberFunctionT0
{
	typedef R (T::*F)() const;
	explicit ConstMemberFunctionT0(F f) :
			m_f(f)
	{
	}
	R operator()(T* p) const
	{
		return (p->*m_f)();
	}
	F m_f;
};

/*
 * This class mapping an object with a member function and to a functor object.
 * This implementation provided 1 argument.
 */
template<class R, class T, class A1>
struct MemberFunctionT1
{
	typedef R (T::*F)(A1);
	explicit MemberFunctionT1(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1) const
	{
		return (p->*m_f)(a1);
	}
	F m_f;
};
/*
 * This class mapping an object with a const member function and to a functor object.
 * This implementation provided 1 argument.
 */
template<class R, class T, class A1>
struct ConstMemberFunctionT1
{
	typedef R (T::*F)(A1) const;
	explicit ConstMemberFunctionT1(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1) const
	{
		return (p->*m_f)(a1);
	}
	F m_f;
};

/*
 * This class mapping an object with a member function and to a functor object.
 * This implementation provided 2 arguments.
 */
template<class R, class T, class A1, class A2>
struct MemberFunctionT2
{
	typedef R (T::*F)(A1, A2);
	explicit MemberFunctionT2(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2) const
	{
		return (p->*m_f)(a1, a2);
	}
	F m_f;
};
/*
 * This class mapping an object with a const member function and to a functor object.
 * This implementation provided 2 arguments.
 */
template<class R, class T, class A1, class A2>
struct ConstMemberFunctionT2
{
	typedef R (T::*F)(A1, A2) const;
	explicit ConstMemberFunctionT2(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2) const
	{
		return (p->*m_f)(a1, a2);
	}
	F m_f;
};

/*
 * This class mapping an object with a member function and to a functor object.
 * This implementation provided 3 arguments.
 */
template<class R, class T, class A1, class A2, class A3>
struct MemberFunctionT3
{
	typedef R (T::*F)(A1, A2, A3);
	explicit MemberFunctionT3(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2, A3 a3) const
	{
		return (p->*m_f)(a1, a2, a3);
	}
	F m_f;
};
/*
 * This class mapping an object with a const member function and to a functor object.
 * This implementation provided 3 arguments.
 */
template<class R, class T, class A1, class A2, class A3>
struct ConstMemberFunctionT3
{
	typedef R (T::*F)(A1, A2, A3) const;
	explicit ConstMemberFunctionT3(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2, A3 a3) const
	{
		return (p->*m_f)(a1, a2, a3);
	}
	F m_f;
};

/*
 * This class mapping an object with a member function and to a functor object.
 * This implementation provided 4 arguments.
 */
template<class R, class T, class A1, class A2, class A3, class A4>
struct MemberFunctionT4
{
	typedef R (T::*F)(A1, A2, A3, A4);
	explicit MemberFunctionT4(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2, A3 a3, A4 a4) const
	{
		return (p->*m_f)(a1, a2, a3, a4);
	}
	F m_f;
};
/*
 * This class mapping an object with a const member function and to a functor object.
 * This implementation provided 4 arguments.
 */
template<class R, class T, class A1, class A2, class A3, class A4>
struct ConstMemberFunctionT4
{
	typedef R (T::*F)(A1, A2, A3) const;
	explicit ConstMemberFunctionT4(F f) :
			m_f(f)
	{
	}
	R operator()(T* p, A1 a1, A2 a2, A3 a3, A4 a4) const
	{
		return (p->*m_f)(a1, a2, a3, a4);
	}
	F m_f;
};

/*
 * This class represents an empty argument list.
 */
class ArgumentListT0
{
public:
	ArgumentListT0()
	{
	}

	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f();
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f();
	}
};

/*
 * This class represents an argument list that stores 1 argument.
 */
template<class A1>
class ArgumentListT1
{
public:
	explicit ArgumentListT1(A1 a1) :
			m_a1(a1)
	{
	}

	A1 operator[](PlaceHolder<1>) const
	{
		return m_a1;
	}
	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f(a[m_a1]);
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f(a[m_a1]);
	}

private:
	A1 m_a1;
};

/*
 * This class represents an argument list that stores 2 arguments.
 */
template<class A1, class A2>
class ArgumentListT2
{
public:
	explicit ArgumentListT2(A1 a1, A2 a2) :
			m_a1(a1), m_a2(a2)
	{
	}

	A1 operator[](PlaceHolder<1>) const
	{
		return m_a1;
	}
	A2 operator[](PlaceHolder<2>) const
	{
		return m_a2;
	}
	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f(a[m_a1], a[m_a2]);
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f(a[m_a1], a[m_a2]);
	}

private:
	A1 m_a1;
	A2 m_a2;
};

/*
 * This class represents an argument list that stores 3 placeholders or values.
 */
template<class A1, class A2, class A3>
class ArgumentListT3
{
public:
	explicit ArgumentListT3(A1 a1, A2 a2, A3 a3) :
			m_a1(a1), m_a2(a2), m_a3(a3)
	{
	}

	A1 operator[](PlaceHolder<1>) const
	{
		return m_a1;
	}
	A2 operator[](PlaceHolder<2>) const
	{
		return m_a2;
	}
	A3 operator[](PlaceHolder<3>) const
	{
		return m_a3;
	}
	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f(a[m_a1], a[m_a2], a[m_a3]);
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f(a[m_a1], a[m_a2], a[m_a3]);
	}

private:
	A1 m_a1;
	A2 m_a2;
	A3 m_a3;
};

/*
 * This class represents an argument list that stores 4 placeholders or values.
 */
template<class A1, class A2, class A3, class A4>
class ArgumentListT4
{
public:
	explicit ArgumentListT4(A1 a1, A2 a2, A3 a3, A4 a4) :
			m_a1(a1), m_a2(a2), m_a3(a3), m_a4(a4)
	{
	}

	A1 operator[](PlaceHolder<1>) const
	{
		return m_a1;
	}
	A2 operator[](PlaceHolder<2>) const
	{
		return m_a2;
	}
	A3 operator[](PlaceHolder<3>) const
	{
		return m_a3;
	}
	A4 operator[](PlaceHolder<4>) const
	{
		return m_a4;
	}
	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f(a[m_a1], a[m_a2], a[m_a3], a[m_a4]);
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f(a[m_a1], a[m_a2], a[m_a3], a[m_a4]);
	}

private:
	A1 m_a1;
	A2 m_a2;
	A3 m_a3;
	A4 m_a4;
};

/*
 * This class represents an argument list that stores 5 placeholders or values.
 */
template<class A1, class A2, class A3, class A4, class A5>
class ArgumentListT5
{
public:
	explicit ArgumentListT5(A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) :
			m_a1(a1), m_a2(a2), m_a3(a3), m_a4(a4), m_a5(a5)
	{
	}

	A1 operator[](PlaceHolder<1>) const
	{
		return m_a1;
	}
	A2 operator[](PlaceHolder<2>) const
	{
		return m_a2;
	}
	A3 operator[](PlaceHolder<3>) const
	{
		return m_a3;
	}
	A4 operator[](PlaceHolder<4>) const
	{
		return m_a4;
	}
	A5 operator[](PlaceHolder<5>) const
	{
		return m_a5;
	}
	template<class T>
	T& operator[](ValueT<T>& v) const
	{
		return v.Get();
	}

	template<class F, class A>
	void operator()(TypeT<void>, F& f, A& a)
	{
		f(a[m_a1], a[m_a2], a[m_a3], a[m_a4], a[m_a5]);
	}
	template<class R, class F, class A>
	R operator()(TypeT<R>, F& f, A& a)
	{
		return f(a[m_a1], a[m_a2], a[m_a3], a[m_a4], a[m_a5]);
	}

private:
	A1 m_a1;
	A2 m_a2;
	A3 m_a3;
	A4 m_a4;
	A5 m_a5;
};

////////////////////////////////////////////////////////////////////////////////
// Bind type.

/*
 * Represents a dynamic function delegate.
 */
template<class R, class F, class L>
class BindT
{
public:
	BindT(F f, L l) :
			m_f(f), m_l(l)
	{
	}

	R operator()()
	{
		ArgumentListT0 a;
		return m_l(TypeT<R>(), m_f, a);
	}
	template<class A1>
	R operator()(const A1& a1)
	{
		ArgumentListT1<const A1&> a(a1);
		return m_l(TypeT<R>(), m_f, a);
	}
	template<class A1, class A2>
	R operator()(const A1& a1, const A2& a2)
	{
		ArgumentListT2<const A1&, const A2&> a(a1, a2);
		return m_l(TypeT<R>(), m_f, a);
	}
	template<class A1, class A2, class A3>
	R operator()(const A1& a1, const A2& a2, const A3& a3)
	{
		ArgumentListT3<const A1&, const A2&, const A3&> a(a1, a2, a3);
		return m_l(TypeT<R>(), m_f, a);
	}
	template<class A1, class A2, class A3, class A4>
	R operator()(const A1& a1, const A2& a2, const A3& a3, const A4& a4)
	{
		ArgumentListT4<const A1&, const A2&, const A3&, const A4&> a(a1, a2, a3, a4);
		return m_l(TypeT<R>(), m_f, a);
	}

private:
	F m_f;
	L m_l;
};

}	//	namespace _PRIV

////////////////////////////////////////////////////////////////////////////////
// Bind functions

/**
 * Predefined placeholders.
 */
static _PRIV::PlaceHolder<1> _1;
static _PRIV::PlaceHolder<2> _2;
static _PRIV::PlaceHolder<3> _3;
static _PRIV::PlaceHolder<4> _4;
static _PRIV::PlaceHolder<5> _5;

/**
 * Bind a function to a functor object. This function equivalent to F();
 *
 * @param f Pointer to the given function.
 * @return The functor object bound to given function with arguments.
 */
template<class R>
_PRIV::BindT<R, R (*)(), _PRIV::ArgumentListT0> Bind(R (*f)())
{
	typedef R (*F)();
	typedef _PRIV::ArgumentListT0 LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(f, LIST_TYPE());
}

/**
 * Bind a function to a functor object. Equivalent to F(A1);
 *
 * @param f Pointer to the given function.
 * @param a1 The first argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class B1, class A1>
_PRIV::BindT<R, R (*)(B1), _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> > Bind(R (*f)(B1), A1 a1)
{
	typedef R (*F)(B1);
	typedef _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(f, LIST_TYPE(a1));
}

/**
 * Bind a function to a functor object. This function equivalent to F(A1, A2);
 *
 * @param f Pointer to the given function.
 * @param a1 The first argument.
 * @param a2 The second argument.
 * @return The functor object bound to given function with arguments
 */
template<class R, class B1, class B2, class A1, class A2>
_PRIV::BindT<R, R (*)(B1, B2),
		_PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> > Bind(
		R (*f)(B1, B2), A1 a1, A2 a2)
{
	typedef R (*F)(B1, B2);
	typedef _PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(f, LIST_TYPE(a1, a2));
}

/**
 * Bind a function to a functor object. This function equivalent to F(A1, A2, A3);
 *
 * @param f Pointer to the given function.
 * @param a1 The first argument.
 * @param a2 The second argument.
 * @param a3 The third argument.
 * @return The functor object bound to given function with arguments
 */
template<class R, class B1, class B2, class B3, class A1, class A2, class A3>
_PRIV::BindT<R, R (*)(B1, B2, B3),
		_PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE> > Bind(R (*f)(B1, B2, B3), A1 a1, A2 a2, A3 a3)
{
	typedef R (*F)(B1, B2, B3);
	typedef _PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(f, LIST_TYPE(a1, a2, a3));
}

/**
 * Bind a function to a functor object. This function equivalent to F(A1, A2, A3, A4);
 *
 * @param f Pointer to the given function.
 * @param a1 The first argument.
 * @param a2 The second argument.
 * @param a3 The third argument.
 * @param a4 The fourth argument.
 * @return The functor object bound to given function with arguments
 */
template<class R, class B1, class B2, class B3, class B4, class A1, class A2, class A3, class A4>
_PRIV::BindT<R, R (*)(B1, B2, B3, B4),
		_PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> > Bind(R (*f)(B1, B2, B3, B4),
		A1 a1, A2 a2, A3 a3, A4 a4)
{
	typedef R (*F)(B1, B2, B3, B4);
	typedef _PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(f, LIST_TYPE(a1, a2, a3, a4));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F();
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class A1>
_PRIV::BindT<R, _PRIV::MemberFunctionT0<R, T>, _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> > Bind(
		R (T::*f)(), A1 a1)
{
	typedef _PRIV::MemberFunctionT0<R, T> F;
	typedef _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1));
}
/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F() const;
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class A1>
_PRIV::BindT<R, _PRIV::ConstMemberFunctionT0<R, T>, _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> > Bind(
		R (T::*f)() const, A1 a1)
{
	typedef _PRIV::ConstMemberFunctionT0<R, T> F;
	typedef _PRIV::ArgumentListT1<typename _PRIV::Argument<A1>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2);
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class A1, class A2>
_PRIV::BindT<R, _PRIV::MemberFunctionT1<R, T, B1>,
		_PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> > Bind(
		R (T::*f)(B1), A1 a1, A2 a2)
{
	typedef _PRIV::MemberFunctionT1<R, T, B1> F;
	typedef _PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2));
}
/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2) const;
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class A1, class A2>
_PRIV::BindT<R, _PRIV::ConstMemberFunctionT1<R, T, B1>,
		_PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> > Bind(
		R (T::*f)(B1) const, A1 a1, A2 a2)
{
	typedef _PRIV::ConstMemberFunctionT1<R, T, B1> F;
	typedef _PRIV::ArgumentListT2<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3);
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class A1, class A2, class A3>
_PRIV::BindT<R, _PRIV::MemberFunctionT2<R, T, B1, B2>,
		_PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE> > Bind(R (T::*f)(B1, B2), A1 a1, A2 a2, A3 a3)
{
	typedef _PRIV::MemberFunctionT2<R, T, B1, B2> F;
	typedef _PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3) const;
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class A1, class A2, class A3>
_PRIV::BindT<R, _PRIV::ConstMemberFunctionT2<R, T, B1, B2>,
		_PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE> > Bind(R (T::*f)(B1, B2) const, A1 a1, A2 a2, A3 a3)
{
	typedef _PRIV::ConstMemberFunctionT2<R, T, B1, B2> F;
	typedef _PRIV::ArgumentListT3<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3, A4);
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @param a4 The third argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class B3, class A1, class A2, class A3, class A4>
_PRIV::BindT<R, _PRIV::MemberFunctionT3<R, T, B1, B2, B3>,
		_PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> > Bind(R (T::*f)(B1, B2, B3),
		A1 a1, A2 a2, A3 a3, A4 a4)
{
	typedef _PRIV::MemberFunctionT3<R, T, B1, B2, B3> F;
	typedef _PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3, a4));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3, A4) const;
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @param a4 The third argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class B3, class A1, class A2, class A3, class A4>
_PRIV::BindT<R, _PRIV::ConstMemberFunctionT3<R, T, B1, B2, B3>,
		_PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> > Bind(
		R (T::*f)(B1, B2, B3) const, A1 a1, A2 a2, A3 a3, A4 a4)
{
	typedef _PRIV::ConstMemberFunctionT3<R, T, B1, B2, B3> F;
	typedef _PRIV::ArgumentListT4<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3, a4));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3, A4, A5);
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @param a4 The third argument.
 * @param a5 The fourth argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class B3, class B4, class A1, class A2, class A3, class A4, class A5>
_PRIV::BindT<R, _PRIV::MemberFunctionT4<R, T, B1, B2, B3, B4>,
		_PRIV::ArgumentListT5<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE,
				typename _PRIV::Argument<A5>::TYPE> > Bind(R (T::*f)(B1, B2, B3, B4), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
{
	typedef _PRIV::MemberFunctionT4<R, T, B1, B2, B3, B4> F;
	typedef _PRIV::ArgumentListT5<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE, typename _PRIV::Argument<A5>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3, a4, a5));
}

/**
 * Bind an object with a member function to a functor object. This function equivalent to A1->F(A2, A3, A4, A5) const;
 *
 * @param f Pointer to the member function.
 * @param a1 The this-pointer of given object.
 * @param a2 The first argument.
 * @param a3 The second argument.
 * @param a4 The third argument.
 * @param a5 The fourth argument.
 * @return The functor object bound to given function with arguments.
 */
template<class R, class T, class B1, class B2, class B3, class B4, class A1, class A2, class A3, class A4, class A5>
_PRIV::BindT<R, _PRIV::ConstMemberFunctionT4<R, T, B1, B2, B3, B4>,
		_PRIV::ArgumentListT5<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
				typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE,
				typename _PRIV::Argument<A5>::TYPE> > Bind(R (T::*f)(B1, B2, B3, B4) const, A1 a1, A2 a2, A3 a3, A4 a4,
		A5 a5)
{
	typedef _PRIV::ConstMemberFunctionT4<R, T, B1, B2, B3, B4> F;
	typedef _PRIV::ArgumentListT5<typename _PRIV::Argument<A1>::TYPE, typename _PRIV::Argument<A2>::TYPE,
			typename _PRIV::Argument<A3>::TYPE, typename _PRIV::Argument<A4>::TYPE, typename _PRIV::Argument<A5>::TYPE> LIST_TYPE;
	return _PRIV::BindT<R, F, LIST_TYPE>(F(f), LIST_TYPE(a1, a2, a3, a4, a5));
}

}	//	namespace BFX

#endif	//	__BIND_H__
